package l1j.server.server.model;

import static l1j.server.server.model.skill.L1SkillId.ABSOLUTE_BARRIER;
import static l1j.server.server.model.skill.L1SkillId.COUNTER_MAGIC;
import static l1j.server.server.model.skill.L1SkillId.EARTH_BIND;
import static l1j.server.server.model.skill.L1SkillId.FREEZING_BLIZZARD;
import static l1j.server.server.model.skill.L1SkillId.FREEZING_BREATH;
import static l1j.server.server.model.skill.L1SkillId.ICE_LANCE;
import static l1j.server.server.model.skill.L1SkillId.ILLUSION_AVATAR;
import static l1j.server.server.model.skill.L1SkillId.STATUS_FREEZE;
import static l1j.server.server.model.skill.L1SkillId.NPC_FREEZING_BREATH;

import l1j.opqlo.Server.L1World.L1World;
import l1j.server.server.ActionCodes;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.datatables.WeaponSkillTable;
import l1j.server.server.model.Instance.L1MonsterInstance;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.model.skill.L1SkillUse;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_EffectLocation;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.serverpackets.S_UseAttackSkill;
import l1j.server.server.templates.L1Skills;
import l1j.server.server.utils.Random;

public class L1WeaponSkill {


	/*
	public static double getAreaSkillWeaponDamage(final L1PcInstance pc,final L1Character cha, final int weaponId) {
		double dmg = 0;
		int probability = 0;
		int attr = 0;
		final int chance = Random.nextInt(100) + 1;
		if (weaponId == 263) { // フリージングランサー
			probability = 5;
			attr = L1Skills.ATTR_WATER;
		} else if (weaponId == 260) { // レイジングウィンド
			probability = 4;
			attr = L1Skills.ATTR_WIND;
		}
		if (probability >= chance) {
			final int sp = pc.getSp();
			final int intel = pc.getInt();
			int area = 0;
			int effectTargetId = 0;
			int effectId = 0;
			L1Character areaBase = cha;
			double damageRate = 0;

			if (weaponId == 263) { // フリージングランサー
				area = 3;
				damageRate = 1.4D;
				effectTargetId = cha.getId();
				effectId = 1804;
				areaBase = cha;
			} else if (weaponId == 260) { // レイジングウィンド
				area = 4;
				damageRate = 1.5D;
				effectTargetId = pc.getId();
				effectId = 758;
				areaBase = pc;
			}
			double bsk = 0;
			if (pc.hasSkillEffect(BERSERKERS)) {
				bsk = 0.2;
			}
			dmg = (intel + sp) * (damageRate + bsk)
			+ Random.nextInt(intel + sp) * damageRate;

			pc.sendPackets(new S_SkillSound(effectTargetId, effectId));
			pc.broadcastPacket(new S_SkillSound(effectTargetId, effectId));

			for (final L1Object object : L1World.getInstance().getVisibleObjects(
					areaBase, area)) {
				if (object == null) {
					continue;
				}
				if (!(object instanceof L1Character)) {
					continue;
				}
				if (object.getId() == pc.getId()) {
					continue;
				}
				if (object.getId() == cha.getId()) { // 攻撃対象は除外
					continue;
				}

				// 攻撃対象がMOBの場合は、範囲内のMOBにのみ当たる
				// 攻撃対象がPC,Summon,Petの場合は、範囲内のPC,Summon,Pet,MOBに当たる
				if (cha instanceof L1MonsterInstance) {
					if (!(object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if (cha instanceof L1PcInstance
						|| cha instanceof L1SummonInstance
						|| cha instanceof L1PetInstance) {
					if (!(object instanceof L1PcInstance
							|| object instanceof L1SummonInstance
							|| object instanceof L1PetInstance || object instanceof L1MonsterInstance)) {
						continue;
					}
				}

				dmg = calcDamageReduction(pc, (L1Character) object, dmg, attr);
				if (dmg <= 0) {
					continue;
				}
				if (object instanceof L1PcInstance) {
					final L1PcInstance targetPc = (L1PcInstance) object;
					targetPc.sendPackets(new S_DoActionGFX(targetPc.getId(),ActionCodes.ACTION_Damage));
					targetPc.broadcastPacket(new S_DoActionGFX(targetPc.getId(), ActionCodes.ACTION_Damage));
					targetPc.receiveDamage(pc, (int) dmg, false);
				} else if (object instanceof L1SummonInstance
						|| object instanceof L1PetInstance
						|| object instanceof L1MonsterInstance) {
					final L1NpcInstance targetNpc = (L1NpcInstance) object;
					targetNpc.broadcastPacket(new S_DoActionGFX(targetNpc.getId(), ActionCodes.ACTION_Damage));
					targetNpc.receiveDamage(pc, (int) dmg);
				}
			}
		}
		return calcDamageReduction(pc, cha, dmg, attr);
	}*/
/*
	public static double getLightningEdgeDamage(final L1PcInstance pc, final L1Character cha) {
		double dmg = 0;
		final int chance = Random.nextInt(100) + 1;
		if (4 >= chance) {
			final int sp = pc.getSp();
			final int intel = pc.getInt();
			double bsk = 0;
			if (pc.hasSkillEffect(BERSERKERS)) {
				bsk = 0.2;
			}
			dmg = (intel + sp) * (2 + bsk) + Random.nextInt(intel + sp) * 2;
			pc.sendPacketsX8(new S_SkillSound(cha.getId(), 10));
		//	pc.sendPackets(new S_SkillSound(cha.getId(), 10));
		//	pc.broadcastPacket(new S_SkillSound(cha.getId(), 10));
		}
		return calcDamageReduction(pc, cha, dmg, L1Skills.ATTR_WIND);
	}*/
/*
	public static void giveArkMageDiseaseEffect(final L1PcInstance pc, final L1Character cha) {
		final int chance = Random.nextInt(1000) + 1;
		int probability = (5 - ((cha.getMr() / 10) * 5)) * 10;
		if (probability == 0) {
			probability = 10;
		}
		if (probability >= chance) {
			final L1SkillUse l1skilluse = new L1SkillUse();
			l1skilluse.handleCommands(pc, 56, cha.getId(), cha.getX(),cha.getY(), null, 0, L1SkillUse.TYPE_GMBUFF);
		}
	}*/
/*
	public static void giveFettersEffect(final L1PcInstance pc, final L1Character cha) {
		final int fettersTime = 8000;
		if (isFreeze(cha)) {// 凍結状態orカウンターマジック中
			return;
		}
		if ((Random.nextInt(100) + 1) <= 2) {
			L1EffectSpawn.getInstance().spawnEffect(81182, fettersTime,cha.getX(), cha.getY(), cha.getMapId(),pc);
			if (cha instanceof L1PcInstance) {
				final L1PcInstance targetPc = (L1PcInstance) cha;
				targetPc.setSkillEffect(STATUS_FREEZE, fettersTime);

				targetPc.sendPacketsX8(new S_SkillSound(targetPc.getId(), 4184));
				//targetPc.broadcastPacket(new S_SkillSound(targetPc.getId(),4184));
				targetPc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_BIND,true));
			} else if (cha instanceof L1MonsterInstance
					|| cha instanceof L1SummonInstance
					|| cha instanceof L1PetInstance) {
				final L1NpcInstance npc = (L1NpcInstance) cha;
				npc.setSkillEffect(STATUS_FREEZE, fettersTime);
				npc.broadcastPacketX8(new S_SkillSound(npc.getId(), 4184));
				npc.setParalyzed(true);
			}
		}
	}
*/
	public static double calcDamageReduction(final L1PcInstance pc, final L1Character cha,double dmg, final int attr) {
		// 凍結状態orカウンターマジック中
		if (isFreeze(cha)) {
			return 0;
		}

		 int def = cha.getExtraDef();

		if(cha instanceof L1PcInstance){
		// MRによるダメージ軽減
		final int mr = cha.getMr();
		final double mrdef = Math.min(400, mr ) / 1000D;
		def +=pc._CastleExtraDef;
		dmg -= dmg * mrdef;
		}

		// 属性によるダメージ軽減
		int resist = 0;
		if (attr == L1Skills.ATTR_EARTH) {
			resist = cha.getEarth();
		} else if (attr == L1Skills.ATTR_FIRE) {
			resist = cha.getFire();
		} else if (attr == L1Skills.ATTR_WATER) {
			resist = cha.getWater();
		} else if (attr == L1Skills.ATTR_WIND) {
			resist = cha.getWind();
		}
		double resistFloor = 0;
		if (resist >= 0) {
			resistFloor = 2 * resist;
		} else {
			resistFloor = 2 * resist;
		}
		dmg -= resistFloor;

		final byte rate = cha.getDmgReduceRate();
		if(cha instanceof L1MonsterInstance){
			dmg -=def;
			if(rate>0){
			dmg /=rate;
			}
		}else if (cha instanceof L1PcInstance) {
			dmg -= Math.max((def/3)*2, Random.nextInt(def));
			dmg =Math.max(dmg/2, 1);

		}
		/*if(pc.isGm()){
		commit(pc,cha,dmg);
		}*/
		dmg = Math.max(1, dmg);
		return dmg;
	}

	private static double calcKiringkuDamageReduction(final L1PcInstance pc, final L1Character cha,double dmg, final int attr) {
		// 凍結状態orカウンターマジック中
		if (isFreeze(cha)) {
			return 0;
		}
		// MRによるダメージ軽減
		final int mr = cha.getMr();
		final double mrdef = Math.min(400, mr ) / 1000D;

		dmg = (dmg - dmg * mrdef) * ( (Random.nextInt(6)+4) *0.1);

		return dmg;
	}

	//TODO 光爆武器強化卷軸魔法改寫
/*	public static double getDamage(final L1PcInstance pc, final L1Character cha) {
		double dmg = 0;
		final int chance = Random.nextInt(100) + 1;
		if (30 >= chance) {
			final int diceCount = 2;
			final int Level = pc.getLevel() / 2;
			double bsk = 0;
			final double damageRate = 1.4D;
			int LvlDmg = 0;
			bsk = 1.2;
			for (int i = 0; i < diceCount; i++) {
				LvlDmg += (Random.nextInt(Level) + 1) * (bsk + damageRate);
			}
			dmg = LvlDmg * damageRate;
			final int attr = 5;
			for (int i = 5; i > 0; i--) {//TODO 要出現幾個特效
				final L1Location newLocation = cha.getLocation().randomLocation(attr, true);//TODO 周圍幾格內出現
				final int getX = newLocation.getX();//TODO 取得隨機x座標
				final int getY = newLocation.getY();//TODO 取得隨機y座標
				final S_EffectLocation spr = new S_EffectLocation(getX, getY, 6288);
				pc.sendPackets(spr);
				pc.broadcastPacket(spr);
			}
			for (final L1Object object : L1World.getInstance().getVisibleObjects(cha, attr)) {
				if (object == null) {
					continue;
				}
				if (!(object instanceof L1Character)) {
					continue;
				}
				if (object.getId() == pc.getId()) {
					continue;
				}
				if (object.getId() == cha.getId()) {//攻撃対象は除外
					continue;
				}
				// 攻撃対象がMOBの場合は、範囲内のMOBにのみ当たる
				// 攻撃対象がPC,Summon,Petの場合は、範囲内のPC,Summon,Pet,MOBに当たる
				if (cha instanceof L1MonsterInstance) {
					if (!(object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if (cha instanceof L1PcInstance
						|| cha instanceof L1SummonInstance
						|| cha instanceof L1PetInstance) {
					if (!(object instanceof L1PcInstance
							|| object instanceof L1SummonInstance
							|| object instanceof L1PetInstance || object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if (dmg <= 0) {
					continue;
				}
				final S_EffectLocation spr = new S_EffectLocation(cha.getX(), cha.getY(), 6288);
				pc.sendPackets(spr);
				pc.broadcastPacket(spr);
				if (object instanceof L1PcInstance) {
					final L1PcInstance targetPc = (L1PcInstance) object;
					targetPc.sendPackets(new S_DoActionGFX(targetPc.getId(),ActionCodes.ACTION_Damage));
					targetPc.broadcastPacket(new S_DoActionGFX(targetPc.getId(), ActionCodes.ACTION_Damage));
					targetPc.receiveDamage(pc, (int) dmg, false);
				} else if (object instanceof L1SummonInstance
						|| object instanceof L1PetInstance
						|| object instanceof L1MonsterInstance) {
					final L1NpcInstance targetNpc = (L1NpcInstance) object;
					targetNpc.broadcastPacket(new S_DoActionGFX(targetNpc.getId(), ActionCodes.ACTION_Damage));
					targetNpc.receiveDamage(pc, (int) dmg);
				}
			}
		}
		return calcDamageReduction(pc, cha, dmg, L1Skills.ATTR_WIND);
	}
	//TODO 光爆武器強化卷軸魔法改寫

	//TODO 冰雨武器強化卷軸魔法改寫
	public static double getBaphometS(final L1PcInstance pc, final L1Character cha) {
		double dmg = 0;
		final int chance = Random.nextInt(100) + 1;
		if (20 >= chance) {
			final int diceCount = 2;
			final int Level = pc.getLevel() / 2;
			double bsk = 0;
			final double damageRate = 1.4D;
			int LvlDmg = 0;
			if (pc.hasSkillEffect(BERSERKERS)) {
				bsk = 0.5;
			}
			for (int i = 0; i < diceCount; i++) {
				LvlDmg += (Random.nextInt(Level) + 1) * (bsk + damageRate);
			}
			dmg = LvlDmg * damageRate;
			final int attr = 1;
			for (int i = 2; i > 0; i--) {//TODO 要出現幾個特效
				final L1Location newLocation = cha.getLocation().randomLocation(attr, true);//TODO 周圍幾格內出現
				final int getX = newLocation.getX();//TODO 取得隨機x座標
				final int getY = newLocation.getY();//TODO 取得隨機y座標
				final S_EffectLocation spr = new S_EffectLocation(getX, getY, 7771);
				pc.sendPackets(spr);
				pc.broadcastPacket(spr);
			}
			for (final L1Object object : L1World.getInstance().getVisibleObjects(cha, attr)) {
				if (object == null) {
					continue;
				}
				if (!(object instanceof L1Character)) {
					continue;
				}
				if (object.getId() == pc.getId()) {
					continue;
				}
				if (object.getId() == cha.getId()) {//攻撃対象は除外
					continue;
				}
				// 攻撃対象がMOBの場合は、範囲内のMOBにのみ当たる
				// 攻撃対象がPC,Summon,Petの場合は、範囲内のPC,Summon,Pet,MOBに当たる
				if (cha instanceof L1MonsterInstance) {
					if (!(object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if (cha instanceof L1PcInstance
						|| cha instanceof L1SummonInstance
						|| cha instanceof L1PetInstance) {
					if (!(object instanceof L1PcInstance
							|| object instanceof L1SummonInstance
							|| object instanceof L1PetInstance || object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if (dmg <= 0) {
					continue;
				}
				final S_EffectLocation spr = new S_EffectLocation(cha.getX(), cha.getY(), 7771);
				pc.sendPackets(spr);
				pc.broadcastPacket(spr);
				if (object instanceof L1PcInstance) {
					final L1PcInstance targetPc = (L1PcInstance) object;
					targetPc.sendPackets(new S_DoActionGFX(targetPc.getId(),ActionCodes.ACTION_Damage));
					targetPc.broadcastPacket(new S_DoActionGFX(targetPc.getId(), ActionCodes.ACTION_Damage));
					targetPc.receiveDamage(pc, (int) dmg, false);
				} else if (object instanceof L1SummonInstance
						|| object instanceof L1PetInstance
						|| object instanceof L1MonsterInstance) {
					final L1NpcInstance targetNpc = (L1NpcInstance) object;
					targetNpc.broadcastPacket(new S_DoActionGFX(targetNpc.getId(), ActionCodes.ACTION_Damage));
					targetNpc.receiveDamage(pc, (int) dmg);
				}
			}
		}
		return calcDamageReduction(pc, cha, dmg, L1Skills.ATTR_FIRE);
	}
	//TODO 冰雨武器強化卷軸魔法改寫

	public static double getBaphometStaffDamage(final L1PcInstance pc, final L1Character cha) {
		double dmg = 0;
		final int chance = Random.nextInt(100) + 1;
		if (20 >= chance) {
			final int locx = cha.getX();
			final int locy = cha.getY();
			final int sp = pc.getSp();
			final int intel = pc.getInt();
			double bsk = 0;
			if (pc.hasSkillEffect(BERSERKERS)) {
				bsk = 0.2;
			}
			dmg = (intel + sp) * (1.8 + bsk) + Random.nextInt(intel + sp)* 1.8;
			final S_EffectLocation packet = new S_EffectLocation(locx, locy, 129);
			pc.sendPackets(packet);
			pc.broadcastPacket(packet);
		}
		return calcDamageReduction(pc, cha, dmg, L1Skills.ATTR_EARTH);
	}*/
/*
	public static double getDiceDaggerDamage(final L1PcInstance pc,final L1PcInstance targetPc, final L1ItemInstance weapon) {
		double dmg = 0;
		final int chance = Random.nextInt(100) + 1;
		if (3 >= chance) {
			dmg = targetPc.getCurrentHp() * 2 / 3;
			if (targetPc.getCurrentHp() - dmg < 0) {
				dmg = 0;
			}
			final String msg = weapon.getLogName();
			pc.sendPackets(new S_ServerMessage(158, msg));
			// \f1%0が蒸発してなくなりました。
			pc.getInventory().removeItem(weapon, 1);
		}
		return dmg;
	}
*/
	public static double getKiringkuDamage(final L1PcInstance pc, final L1Character cha) {
		int dmg = 0;
		final int dice = 5;
		final int diceCount = 2;
		final int value = 14;
		int kiringkuDamage = 0;
		int charaIntelligence = 0;
		//final int getTargetMr = 0;
		// XXX ダイスと値は本来、キーリンク毎に違うが不明な為、判明しているDSKのものに固定。

		for (int i = 0; i < diceCount; i++) {
			kiringkuDamage += Random.nextInt(dice) + 1;
		}
		kiringkuDamage += value;

		charaIntelligence = pc.getInt() + pc.getSp() - pc.getTrueSp()- 12;
		if (charaIntelligence < 1) {
			charaIntelligence = 1;
		}

		kiringkuDamage *= 1.0 + charaIntelligence * 3.0 / 32.0;

		final double kiringkuFloor = Math.floor(kiringkuDamage);

		dmg += kiringkuFloor + pc.getWeapon().getEnchantLevel();

		switch (pc.getWeapon().getItem().getGfxId()) {
		case 3018:// 藍寶石奇古獸
			pc.sendPacketsX8(new S_SkillSound(pc.getId(), 6983));
			break;

		default:
			pc.sendPacketsX8(new S_SkillSound(pc.getId(), 7049));
			break;
		}
		if (pc.hasSkillEffect(ILLUSION_AVATAR)) {
			dmg += 10;
		}

		return calcKiringkuDamageReduction(pc, cha, dmg, 0);
	}

	public static double getWeaponSkillDamage(final L1PcInstance pc, final L1Character cha,final int weaponId) {
		final L1WeaponSkill weaponSkill = WeaponSkillTable.getInstance().getTemplate(weaponId);
		if (pc == null || cha == null || weaponSkill == null) {
			return 0;
		}

		int probability = weaponSkill.getProbability();
		final int bless =pc.getWeapon().getBless();
		if(bless==0 || bless==128){
			probability +=10;
		}
		if (probability < Random.nextInt(105) + 1) {
			return 0;
		}
		int chaId = 0;
		if (weaponSkill.getEffectId() != 0) {
			final int effectId = weaponSkill.getEffectId();
			if (weaponSkill.getEffectTarget() == 0) {
				chaId = cha.getId();
			} else {
				chaId = pc.getId();
			}
			if (!weaponSkill.isArrowType()) {
				pc.sendWeaponEffectPackets(new S_SkillSound(chaId, effectId) , cha);
			} else {
//				pc.sendPacketsX8(new S_UseAttackSkill(pc, chaId,effectId, cha.getX(), cha.getY(),ActionCodes.ACTION_Attack, false));
				pc.sendWeaponEffectPackets(new S_UseAttackSkill(pc, chaId,effectId, cha.getX(), cha.getY(),ActionCodes.ACTION_Attack, false) , cha);
			}
			if(effectId == 10707){
				final int X = cha.getX(), Y = cha.getY();
				S_EffectLocation skill = null ;
				for(int i =5 ; i>0; i--){
					switch(i){
					//10707
					case 1:
						skill = new S_EffectLocation(X+3 , Y , 9823);
						break;
					case 2:
						skill = new S_EffectLocation(X , Y+3 , 9823);
						break;
					case 3:
						skill = new S_EffectLocation(X-3 , Y , 9823);
						break;
					case 4:
						skill = new S_EffectLocation(X , Y-3 , 9823);
						break;
					case 5:
						pc.sendWeaponEffectPackets(new S_SkillSound(cha.getId() ,6574) , cha);
						break;
					}
					if(skill != null){
					pc.sendWeaponEffectPackets(skill , cha);
					}

				}
				skill = null;
			}else if(effectId == 4223){
				final int X = cha.getX(), Y = cha.getY();
				S_EffectLocation skill = null ;

				for(int i=4; i>0; i--){

					switch(i){
					case 1:
						skill = new S_EffectLocation(X+2 , Y , 172);
						break;
					case 2:
						skill = new S_EffectLocation(X-2 , Y , 172);
						break;
					case 3:
						skill = new S_EffectLocation(X , Y+2 , 172);
						break;
					case 4:
						skill = new S_EffectLocation(X , Y-2 , 172);
						break;
					}
					if(skill != null){
						pc.sendWeaponEffectPackets(skill , cha);
				}
			}
				skill = null;
			}else if(effectId == 1791){
				final int X = cha.getX(), Y = cha.getY();
				S_EffectLocation skill = null ;

				for(int i=4; i>0; i--){

					switch(i){
					case 1:
						skill = new S_EffectLocation(X+2 , Y , 168);
						break;
					case 2:
						skill = new S_EffectLocation(X-2 , Y , 168);
						break;
					case 4:
						skill = new S_EffectLocation(X , Y+2 , 168);
						break;
					case 5:
						skill = new S_EffectLocation(X , Y-2 , 168);
						break;
					}
					if(skill != null){
						pc.sendWeaponEffectPackets(skill , cha);
				}
			}
				skill = null;
			}
		}
		//TODO 增加顯示圖案
		final boolean Target = weaponSkill.getGfxIdTarget();
		if (weaponSkill.getGfxId() > 0) {
			if (weaponSkill.getGfxIdTarget()) {//TODO 目標顯示
				chaId = cha.getId();
			} else {
				chaId = pc.getId();
			}
				pc.sendWeaponEffectPackets(new S_SkillSound(chaId, weaponSkill.getGfxId()) , cha);
		}
		if (weaponSkill.get_castgfx() > 0) {
			if (Target) {//TODO 目標顯示
				chaId = cha.getId();
			} else {
				chaId = pc.getId();
			}
				pc.sendWeaponEffectPackets(new S_SkillSound(chaId, weaponSkill.get_castgfx()) , cha);
		}
		if (weaponSkill.get_castgfx2() > 0) {
			if (Target) {//TODO 目標顯示
				chaId = cha.getId();
			} else {
				chaId = pc.getId();
			}
				pc.sendWeaponEffectPackets(new S_SkillSound(chaId, weaponSkill.get_castgfx2()) , cha);
		}
		//TODO 增加顯示圖案

		double damage = 0;
		final int randomDamage = weaponSkill.getRandomDamage()+pc._CastleweaponSkillDmg;
		if (randomDamage != 0) {
			damage = Random.nextInt(randomDamage);
		}
		damage += weaponSkill.getFixDamage();

		final int area = weaponSkill.getArea();

		/*
		if (weaponSkill.getRefStr() > 0) {//TODO 力量加成
			//opqlo 七屬性破127
			final short Str = pc.getStr();
			damage += Str * weaponSkill.getRefStr();
		}
		if (weaponSkill.getRefDex() > 0) {//TODO 敏捷加成
			//opqlo 七屬性破127
			final short Dex = pc.getDex();
			damage += Dex * weaponSkill.getRefDex();
		}
		if (weaponSkill.getRefInt() > 0) {//TODO 智力加成
			//opqlo 七屬性破127
			final short Int = pc.getInt();
			damage += Int * weaponSkill.getRefInt();
		}
		if (weaponSkill.getRefWis() > 0) {//TODO 精神加成
			//opqlo 七屬性破127
			final short Wis = pc.getWis();
			damage += Wis * weaponSkill.getRefWis();
		}*/

		if (area > 0 || area == -1) { // 範囲の場合
			for (final L1Object object : L1World.getInstance().getVisibleObjects(cha,area)) {
				if (object == null) {
					continue;
				}
				if (!(object instanceof L1Character)) {
					continue;
				}
				if (object.getId() == pc.getId()) {
					continue;
				}
				if (object.getId() == cha.getId()) { // 攻撃対象はL1Attackで処理するため除外
					continue;
				}

				// 攻撃対象がMOBの場合は、範囲内のMOBにのみ当たる
				// 攻撃対象がPC,Summon,Petの場合は、範囲内のPC,Summon,Pet,MOBに当たる
				if (cha instanceof L1MonsterInstance) {
					if (!(object instanceof L1MonsterInstance)) {
						continue;
					}
				}
				if (cha instanceof L1PcInstance
						|| cha instanceof L1SummonInstance
						|| cha instanceof L1PetInstance) {
					if (!(object instanceof L1PcInstance
							|| object instanceof L1SummonInstance
							|| object instanceof L1PetInstance || object instanceof L1MonsterInstance)) {
						continue;
					}
				}


				damage = calcDamageReduction(pc, (L1Character) object, damage,weaponSkill.getAttr());

				if (damage <= 0) {
					continue;
				}
				if (object instanceof L1PcInstance) {
					final L1PcInstance targetPc = (L1PcInstance) object;
					final S_DoActionGFX doGFX = new S_DoActionGFX(targetPc.getId(),ActionCodes.ACTION_Damage);
					targetPc.sendPackets(doGFX);
					targetPc.broadcastPacketAll(doGFX);
					targetPc.receiveDamage(pc, (int) damage, false);
				} else if (object instanceof L1SummonInstance
						|| object instanceof L1PetInstance
						|| object instanceof L1MonsterInstance) {
					final L1NpcInstance targetNpc = (L1NpcInstance) object;
					targetNpc.broadcastPacketAll(new S_DoActionGFX(targetNpc.getId(), ActionCodes.ACTION_Damage));
					targetNpc.receiveDamage(pc, (int) damage);
				}
				pc.sendWeaponEffectPackets(new S_SkillSound(chaId, weaponSkill.get_castgfx2()) , (L1Character) object);
			}
		}


		final int skillId = weaponSkill.getSkillId();
		if (skillId > 0) {
			/*if (skill != null && skill.getTarget().equals("buff")) {
				if (!isFreeze(cha)) { // 凍結状態orカウンターマジック中
					cha.setSkillEffect(skillId,weaponSkill.getSkillTime() * 1000);
				}
			}*/
			if(SkillsTable.getInstance().getTemplate(skillId) !=null){
			new L1SkillUse().handleCommands(pc, skillId, cha.getId(), cha.getX(), cha.getY(),null,weaponSkill.getSkillTime(), L1SkillUse.TYPE_GMBUFF);
			}
		}

		return calcDamageReduction(pc, cha, damage, weaponSkill.getAttr());
	}

	private static boolean isFreeze(final L1Character cha) {
		if (cha.hasSkillEffect(STATUS_FREEZE)) {
			return true;
		}
		if (cha.hasSkillEffect(ABSOLUTE_BARRIER)) {
			return true;
		}
		if (cha.hasSkillEffect(ICE_LANCE)) {
			return true;
		}
		if (cha.hasSkillEffect(FREEZING_BLIZZARD)) {
			return true;
		}
		if (cha.hasSkillEffect(FREEZING_BREATH)) {
			return true;
		}
		if (cha.hasSkillEffect(EARTH_BIND)) {
			return true;
		}
		if (cha.hasSkillEffect(NPC_FREEZING_BREATH)){
			return true;
		}

		// カウンターマジック判定
		if (cha.hasSkillEffect(COUNTER_MAGIC)) {
			cha.removeSkillEffect(COUNTER_MAGIC);
			final int castgfx = SkillsTable.getInstance().getTemplate(COUNTER_MAGIC).getCastGfx();
			cha.broadcastPacketAll(new S_SkillSound(cha.getId(), castgfx));
		//	new L1EffectGFX_S().EffectGFX(cha,cha , castgfx);//opqlo 特效另開線程
			if (cha instanceof L1PcInstance) {
				final L1PcInstance pc = (L1PcInstance) cha;
				pc.sendPackets(new S_SkillSound(pc.getId(), castgfx));
			}
			return true;
		}
		return false;
	}
	/* ■■■■■■■■■■■■■■■ 計算結果反映 ■■■■■■■■■■■■■■■

	private static void commit(final L1PcInstance pc, final L1Character cha,final double damage) {


		// ダメージ値及び命中率確認用メッセージ
		//TODO 設定GM是否顯示傷害訊息
		if (!Config.ALT_ATKMSG) {
			return;
		}
		String msg1 = ""+((damage / cha.getMaxHp())*100);
		msg1 = msg1.substring(0, 4);

		final String msg2 = "傷害:["+(int)damage;
		final String msg3 =  "]["+msg1 +" %]";


		pc.sendPackets(new S_ServerMessage(166, msg2, msg3)); // \f1%0が%4%1%3 %2

	}
	//TODO 設定GM是否顯示傷害訊息
*/

	private final int _weaponId;

	private final int _probability;

	private final int _fixDamage;

	private final int _randomDamage;

	private final int _area;

	private final int _skillId;

	private final int _skillTime;
	private final int _effectId;
	private final int _effectTarget; // エフェクトの対象 0:相手 1:自分
	private final boolean _isArrowType;

	private final int _attr;
	//TODO 武器傷害能力值加成及負面效果
	private final int _gfxId;

	private int _castgfx;

	private int _castgfx2;

	private final boolean _gfxIdTarget;

	//TODO 增加武器技能欄位新增
	private int _refStr = 0;

	private int _refInt = 0;

	private int _refWis = 0;

	private int _refDex = 0;

	public L1WeaponSkill(final int weaponId, final int probability, final int fixDamage,
			final int randomDamage, final int area, final int skillId, final int skillTime,
			final int effectId, final int effectTarget, final boolean isArrowType, final int attr,
			final int gfxId,final int castgfx,final int castgfx2,final boolean gfxIdTarget,final int refStr,final int refInt,
			final int refWis, final int refDex) {

		//TODO 增加武器技能欄位新增
		this._gfxId = gfxId;
		this._castgfx = castgfx;
		this._castgfx2 = castgfx2;
		this._gfxIdTarget = gfxIdTarget;
		this._refStr = refStr;
		this._refInt = refInt;
		this._refWis = refWis;
		this._refDex = refDex;
		//TODO 增加武器技能欄位新增
		this._weaponId = weaponId;
		this._probability = probability;
		this._fixDamage = fixDamage;
		this._randomDamage = randomDamage;
		this._area = area;
		this._skillId = skillId;
		this._skillTime = skillTime;
		this._effectId = effectId;
		this._effectTarget = effectTarget;
		this._isArrowType = isArrowType;
		this._attr = attr;
	}

	public int get_castgfx() {
		return this._castgfx;
	}

	public int get_castgfx2() {
		return this._castgfx2;
	}

	public int getArea() {
		return this._area;
	}

	public int getAttr() {
		return this._attr;
	}

	public int getEffectId() {
		return this._effectId;
	}

	public int getEffectTarget() {
		return this._effectTarget;
	}

	public int getFixDamage() {
		return this._fixDamage;
	}

	public int getGfxId() {
		return this._gfxId;
	}

	//TODO 增加武器技能欄位新增

	public boolean getGfxIdTarget() {
		return this._gfxIdTarget;
	}

	public int getProbability() {
		return this._probability;
	}

	public int getRandomDamage() {
		return this._randomDamage;
	}

	public int getRefDex() {
		return this._refDex;
	}

	public int getRefInt() {
		return this._refInt;
	}

	public int getRefStr() {
		return this._refStr;
	}

	public int getRefWis() {
		return this._refWis;
	}

	public int getSkillId() {
		return this._skillId;
	}

	public int getSkillTime() {
		return this._skillTime;
	}

	public int getWeaponId() {
		return this._weaponId;
	}

	public boolean isArrowType() {
		return this._isArrowType;
	}

	public void set_castgfx(final int _castgfx) {
		this._castgfx = _castgfx;
	}

	public void set_castgfx2(final int _castgfx2) {
		this._castgfx2 = _castgfx2;
	}
	//TODO 武器傷害能力值加成及負面效果

	public void setRefDex(final int int1) {
		this._refDex = int1;
	}
	public void setRefInt(final int int1) {
		this._refInt = int1;
	}
	public void setRefStr(final int int1) {
		this._refStr = int1;
	}

	public void setRefWis(final int int1) {
		this._refWis = int1;
	}

}
